package com.springboot.framework.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.springboot.framework.constant.Const;
import com.springboot.framework.dao.entity.Order;
import com.springboot.framework.dao.entity.OrderDetail;
import com.springboot.framework.dao.mapper.OrderDetailMapper;
import com.springboot.framework.dao.mapper.OrderMapper;
import com.springboot.framework.enums.CouponsEnum;
import com.springboot.framework.enums.Errors;
import com.springboot.framework.enums.StatusEnum;
import com.springboot.framework.exception.BusinessException;
import com.springboot.framework.model.*;
import com.springboot.framework.service.*;
import com.springboot.framework.utils.KeyUtil;
import com.springboot.framework.utils.MapUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author SWF
 * @Date 2019/6/10 11:06
 **/
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private OrderDetailMapper orderDetailMapper;

    @Resource
    private ProductService productService;

    @Resource
    private BuyerAddressService buyerAddressService;

    @Resource
    private PushMessageService pushMessageService;

    @Resource
    private ShopService shopService;

    @Resource
    private UserCouponsService userCouponsService;

    /**
     * 创建订单 买家
     *
     * @return
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public OrderModel create(OrderModel orderModel) {
        // 店铺信息查询并校验
        ShopModel shopModel = shopService.checkShopStatus(orderModel.getShopId());
        // 收货地址校验
        UserAddressModel userAddressModel = checkUserAddress(orderModel, shopModel);
        // 生成订单号
        String orderId = KeyUtil.genUniqueKey();
        // 订单详情入库,并返回“订单总价”
        BigDecimal orderAmount = insertOrderDetail(orderModel.getOrderDetailModels(),orderId);
        // 订单赋值入库
        orderModel.setId(orderId);
        orderModel.setOrderAmount(orderAmount);
        orderModel.setShopContact(shopModel.getContact());
        orderModel.setUserAddress(userAddressModel.getAreaName() + userAddressModel.getAddress());
        orderModel.setUserName(userAddressModel.getContactName());
        orderModel.setUserPhone(userAddressModel.getContactPhone());
        orderModel.setOrderStatus(StatusEnum.ORDER_UNPAID.getCode());
        orderModel.setPayStatus(StatusEnum.PAY_WAIT.getCode());
        // 优惠券校验,并返回“优惠金额”
        if (orderModel.getUserCouponsId() != null) {
            BigDecimal couponsAmount = checkUserCoupons(orderModel,shopModel.getId(),orderAmount);
            orderModel.setCouponsAmount(couponsAmount);
            orderModel.setPayableAmount(orderAmount.subtract(couponsAmount));
        } else {
            orderModel.setPayableAmount(orderAmount);
        }
        orderMapper.insertSelective(convertOrderFromOrderModel(orderModel));
        // 【推送新订单通知】修改为支付后推送
        return orderModel;
    }

    /**
     * 查询单个订单
     *
     * @param orderId
     * @return
     */
    @Override
    public OrderModel get(String orderId) {
        Example example = new Example(Order.class);
        example.and().andEqualTo("id", orderId);
        Order order = orderMapper.selectOneByExample(example);
        if (order == null) {
            throw new BusinessException(Errors.ORDER_NOT_EXIST);
        }
        OrderModel orderModel = convertOrderModelFromOrder(order);

        return orderModel;
    }

    /**
     * 根据店铺查看订单
     *
     * @param shopId
     * @return
     */
    @Override
    public PageInfo listByShopId(Integer shopId, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum,pageSize);
        Example example = new Example(Order.class);
        example.and().andEqualTo("shopId", shopId);
        example.orderBy("id").desc();
        List<Order> orders = orderMapper.selectByExample(example);
        PageInfo pageInfo = new PageInfo(orders);
        List<OrderModel> orderModels = convertOrderModelFromOrder(orders);
        pageInfo.setList(orderModels);
        return pageInfo;
    }

    /**
     * 查看待发货or待收货的订单
     * @param shopId
     * @return
     */
    @Override
    public List<OrderModel> listUnfilledAndUnreceivedByShopId(Integer shopId) {
        Example example = new Example(Order.class);
        example.and().andEqualTo("shopId", shopId);
        example.and().andEqualTo("orderStatus", StatusEnum.ORDER_UNFILLED.getCode())
                .orEqualTo("orderStatus", StatusEnum.ORDER_UNRECEIVED.getCode());
        example.orderBy("id").desc();
        List<Order> orders = orderMapper.selectByExample(example);
        return convertOrderModelFromOrder(orders);
    }

    /**
     * 根据店铺查看订单并排序
     *
     * @param shopId
     * @return
     */
    @Override
    public List<OrderModel> listByShopIdAndSort(Integer shopId) {
        // 权限校验
        List<Order> orders = orderMapper.selectAndSortAndGroup(shopId);
        return convertOrderModelFromOrder(orders);
    }

    /**
     * 根据店铺,订单状态查看订单
     *
     * @param shopId      店铺id
     * @param orderStatus 订单状态
     * @return
     */
    @Override
    public List<OrderModel> listByShopIdAndStatus(Integer shopId, Byte orderStatus) {
        Example example = new Example(Order.class);
        example.and().andEqualTo("shopId", shopId)
                .andEqualTo("orderStatus", orderStatus);
        example.orderBy("id").desc();
        List<Order> orders = orderMapper.selectByExample(example);
        return convertOrderModelFromOrder(orders);
    }

    /**
     * 根据用户查看订单
     *
     * @param userId
     */
    @Override
    public List<OrderModel> listByUserId(Integer userId) {
        Example example = new Example(Order.class);
        example.and().andEqualTo("userId", userId);
        example.orderBy("id").desc();
        List<Order> orders = orderMapper.selectByExample(example);
        return convertOrderModelFromOrder(orders);
    }

    @Override
    public List<OrderModel> listByUserIdAndStatus(Integer userId, Byte orderStatus) {
        Example example = new Example(Order.class);
        example.and().andEqualTo("userId", userId)
                .andEqualTo("orderStatus", orderStatus);
        if (orderStatus >= StatusEnum.ORDER_FINISHED.getCode()) {
            // 如果查询的为已完成或者已取消的订单，则按照完成/取消时间(更新时间)排序
            example.orderBy("updateDate").desc();
        } else {
            example.orderBy("id").desc();
        }
        List<Order> orders = orderMapper.selectByExample(example);
        return convertOrderModelFromOrder(orders);
    }

    /**
     * 取消订单
     *
     * @param orderModel
     */
    @Override
    public OrderModel cancel(OrderModel orderModel) {
        // 【判断订单状态】 当订单为未付款或已付款未被接单时，可以取消订单
        if (orderModel.getOrderStatus() > StatusEnum.ORDER_UNFILLED.getCode()) {
            throw new BusinessException(Errors.ORDER_STATUS_ERROR);
        }
        // 修改订单状态
        orderModel.setOrderStatus(StatusEnum.ORDER_CANCEL.getCode());
        Order order = convertOrderFromOrderModelForUpdateStatus(orderModel);
        orderMapper.updateByPrimaryKeySelective(order);
//        // 返回库存
//        for(OrderDetailModel orderDetailModel : orderModel.getOrderDetailModels()){
//            productService.increaseStock(orderDetailModel.getProductId(),orderDetailModel.getQuantity());
//        }
        // 优惠券返回
        if (orderModel.getUserCouponsId() != null) {
            userCouponsService.updateStatus(orderModel.getUserCouponsId(), CouponsEnum.STATUS_UNUSED.getCode());
        }
        // TODO 退款
        return orderModel;
    }

    /**
     * 完结订单
     *
     * @param orderModel
     * @return
     */
    @Override
    public OrderModel finish(OrderModel orderModel) {
        // 【判断订单状态】当订单为已接单(待收货)时，才可以完结订单
        if (!orderModel.getOrderStatus().equals(StatusEnum.ORDER_UNRECEIVED.getCode())) {
            throw new BusinessException(Errors.ORDER_STATUS_ERROR);
        }
        // 修改订单状态
        orderModel.setOrderStatus(StatusEnum.ORDER_FINISHED.getCode());
        Order order = convertOrderFromOrderModelForUpdateStatus(orderModel);
        orderMapper.updateByPrimaryKeySelective(order);
        return orderModel;
    }

    /**
     * 接收订单
     *
     * @param orderModel
     * @return
     */
    @Override
    public OrderModel receive(OrderModel orderModel) {
        // 【判断订单状态】当订单为已付款时，才可以接收订单
        if (!orderModel.getOrderStatus().equals(StatusEnum.ORDER_UNFILLED.getCode())) {
            throw new BusinessException(Errors.ORDER_STATUS_ERROR);
        }
        // 修改订单状态
        orderModel.setOrderStatus(StatusEnum.ORDER_UNRECEIVED.getCode());
        Order order = convertOrderFromOrderModelForUpdateStatus(orderModel);
        orderMapper.updateByPrimaryKeySelective(order);
        return orderModel;
    }

    /**
     * 支付订单
     *
     * @param orderModel
     * @return
     */
    @Override
    public OrderModel paid(OrderModel orderModel) {
        // 【判断订单状态】当订单为未付款时，才可以支付订单
        if (!orderModel.getOrderStatus().equals(StatusEnum.ORDER_UNPAID.getCode())) {
            throw new BusinessException(Errors.ORDER_STATUS_ERROR);
        }
        // 修改订单状态
        orderModel.setOrderStatus(StatusEnum.ORDER_UNFILLED.getCode());
        Order order = convertOrderFromOrderModelForUpdateStatus(orderModel);
        order.setPayStatus(StatusEnum.PAY_SUCCESS.getCode());
        orderMapper.updateByPrimaryKeySelective(order);
        // 推送新订单通知
        pushMessageService.newOrder(orderModel);
        return orderModel;
    }

    /**
     * 校验用户地址
     * @param orderModel 订单
     * @param shopModel 操作店铺
     * @return 用户地址DTO
     */
    private UserAddressModel checkUserAddress(OrderModel orderModel, ShopModel shopModel) {
        // 查询用户地址
        UserAddressModel userAddressModel = buyerAddressService.get(orderModel.getUserWechatOpenid(), orderModel.getUserAddress());
        if (userAddressModel == null) {
            throw new BusinessException("地址错误");
        }
        // 计算用户到店铺的距离
        String distance = MapUtil.computeDistanceByGeocode(shopModel.getLongitude().doubleValue(),
                shopModel.getLatitude().doubleValue(),
                userAddressModel.getLongitude().doubleValue(),
                userAddressModel.getLatitude().doubleValue());
        if (Integer.parseInt(distance) > Const.DISTRIBUTION_DISTANCE) {
            throw new BusinessException("超出配送范围");
        }
        return userAddressModel;
    }

    /**
     * 订单详情入库orderdetail
     * @param orderDetailModels 商品列表
     * @param orderId   订单id
     * @return 订单总金额
     */
    private BigDecimal insertOrderDetail(List<OrderDetailModel> orderDetailModels, String orderId){
        BigDecimal orderAmount = new BigDecimal(BigInteger.ZERO);
        for (OrderDetailModel orderDetailModel : orderDetailModels) {
            ProductModel productModel = productService.get(orderDetailModel.getProductId());
            if (productModel == null) {
                throw new BusinessException(Errors.PRODUCT_NOT_EXIST);
            }
            // 检查库存，扣库存
            //productService.decreaseStock(orderDetail.getProductId() , orderDetail.getQuantity());
            // 计算总价
            orderAmount = productModel.getPrice().multiply(new BigDecimal(orderDetailModel.getQuantity())).add(orderAmount);
            // 入库
            orderDetailModel.setOrderId(orderId);
            orderDetailModel.setPrice(productModel.getPrice());
            orderDetailModel.setProductName(productModel.getName());
            orderDetailModel.setCover(productModel.getCover());
            orderDetailModel.setIntroduction(productModel.getIntroduction());
            OrderDetail orderDetail = new OrderDetail();
            BeanUtils.copyProperties(orderDetailModel, orderDetail);
            orderDetailMapper.insertSelective(orderDetail);
        }
        return orderAmount;
    }

    /**
     * 校验用户优惠券
     * @param orderModel 订单
     * @param shopId 操作店铺id
     * @param orderAmount 订单总金额
     * @return 优惠金额
     */
    private BigDecimal checkUserCoupons(OrderModel orderModel, Integer shopId, BigDecimal orderAmount){
        UserCouponsModel userCouponsModel = userCouponsService.get(orderModel.getUserCouponsId());
        if (userCouponsModel == null) {
            throw new BusinessException("无效优惠券");
        }
        if (!userCouponsModel.getUserId().equals(orderModel.getUserId())) {
            log.warn("【使用优惠券】优惠券归属为:{}，不属于该用户:{}",userCouponsModel.getUserId(),orderModel.getUserId());
            throw new BusinessException("无效优惠券");
        }
        if (CouponsEnum.SCOPE_SHOP.getCode().equals(userCouponsModel.getCouponsScope())) {
            // 如果适用范围为店铺
            if (!userCouponsModel.getShopId().equals(shopId)) {
                log.warn("【使用优惠券】该优惠券不能在此店铺使用，userId:{}", orderModel.getUserId());
                throw new BusinessException("该优惠券不能在此店铺使用");
            }
        }
        Date nowDate = new Date();
        if (userCouponsModel.getEffectiveDate().after(nowDate) | userCouponsModel.getExpiryDate().before(nowDate)) {
            throw new BusinessException("该优惠券不在使用期限内");
        }
        if (orderAmount.compareTo(new BigDecimal(userCouponsModel.getMinimumAmount())) < 0) {
            throw new BusinessException("订单金额未达到最低限制");
        }
        BigDecimal couponsAmount = userCouponsModel.getCouponsAmount();
        // 修改优惠券状态
        userCouponsService.updateStatus(orderModel.getUserCouponsId(), CouponsEnum.STATUS_USED.getCode());
        return couponsAmount;
    }

    private OrderModel convertOrderModelFromOrder(Order order) {
        if (order == null) {
            return null;
        }
        OrderModel orderModel = new OrderModel();
        BeanUtils.copyProperties(order, orderModel);
        orderModel.convertType();
        // 查询订单详情
        Example example = new Example(OrderDetail.class);
        example.and().andEqualTo("orderId", order.getId());
        List<OrderDetail> orderDetails = orderDetailMapper.selectByExample(example);
        List<OrderDetailModel> orderDetailModels = orderDetails.stream().map(e -> {
            OrderDetailModel orderDetailModel = new OrderDetailModel();
            BeanUtils.copyProperties(e, orderDetailModel);
            // TODO 临时赋值
            orderDetailModel.setName(e.getProductName());
            orderDetailModel.setStock(e.getQuantity());
            return orderDetailModel;
        }).collect(Collectors.toList());
        orderModel.setOrderDetailModels(orderDetailModels);
        return orderModel;
    }

    private List<OrderModel> convertOrderModelFromOrder(List<Order> orders) {
        if (orders == null) {
            return null;
        }
        List<OrderModel> orderModels = orders.stream()
                .map(e -> convertOrderModelFromOrder(e))
                .collect(Collectors.toList());
        return orderModels;
    }

    private Order convertOrderFromOrderModelForUpdateStatus(OrderModel orderModel) {
        Order order = new Order();
        order.setId(orderModel.getId());
        order.setOrderStatus(orderModel.getOrderStatus());
        return order;
    }

    private Order convertOrderFromOrderModel(OrderModel orderModel) {
        Order order = new Order();
        BeanUtils.copyProperties(orderModel, order);
        return order;
    }
}
